package com.ce.source.analysis.thread;

import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.*;

/**
 * @author ：前世小和尚（xiaopingzhang8@creditease.cn）
 * @Description ：观察者线程处理 一个主线程多个子线程
 * @ClassName ：ObserveThread
 * @Company ：普信恒业科技发展（北京）有限公司
 * @date ：2018/3/5 18:24
 */
public class ObserveThread extends Observable {
    private boolean shutDown = false;
    public static CountDownLatch latch = new CountDownLatch(2);

    public static void main(String[] args) throws Exception {
        ObserveThread parent = new ObserveThread();
        try {
            parent.addObserver(new ChildThread());
            parent.addObserver(new ChildThread2());
            parent.setChanged();
            parent.notifyObservers();
        } catch (Exception e) {
            System.out.println("deal exception");
//            parent.setShutDown(true);
//            parent.notifyObservers("rollback");
        }
        latch.await();
        System.out.println("hahah" + parent.isShutDown());
    }

    public boolean isShutDown() {
        return shutDown;
    }

    public void setShutDown(boolean shutDown) {
        this.shutDown = shutDown;
    }
}

class ChildThread extends Thread implements Observer {

    private ObserveThread parent = null;

    public ChildThread() {
        super();
    }

    public ChildThread(ObserveThread parent) {
        this.parent = parent;
    }

    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param o   the observable object.
     * @param arg an argument passed to the <code>notifyObservers</code>
     */
    public void update(Observable o, Object arg) {
        ObserveThread parent = (ObserveThread) o;
        System.out.println(parent.isShutDown());
        Future f = new ScheduledThreadPoolExecutor(1).submit(new Callable() {
            public Object call() throws Exception {
                System.out.println(Thread.currentThread().getName() + " is running");
                try {
                    Thread.sleep(10000);
                    int a = 1 / 0;
                } catch (Exception e) {
                    System.out.println(Thread.currentThread().getName() + " 抛出了异常，即将中断线程操作执行回滚");
                    throw e;
                } finally {
                    ObserveThread.latch.countDown();
                }
                return null;
            }
        });
        try {
            if (f.get() != null) {
                throw new RuntimeException("抛出了runTimeException");
            }
        } catch (Exception e) {
            throw new RuntimeException("抛出了runTimeException");
        }
    }

    /**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see #start()
     * @see #stop()
     * @see #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " is running");
        try {
            Thread.sleep(10000);
            int a = 1 / 0;
        } catch (Exception e) {
            parent.setShutDown(true);
            System.out.println(Thread.currentThread().getName() + " 抛出了异常，即将中断线程操作执行回滚");
        } finally {
            ObserveThread.latch.countDown();
        }
    }
}

class ChildThread2 extends Thread implements Observer {

    private ObserveThread parent = null;

    public ChildThread2() {
        super();
    }

    public ChildThread2(ObserveThread parent) {
        this.parent = parent;
    }

    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param o   the observable object.
     * @param arg an argument passed to the <code>notifyObservers</code>
     */
    public void update(Observable o, Object arg) {
        ObserveThread parent = (ObserveThread) o;
        System.out.println(parent.isShutDown());
        Future f = new ScheduledThreadPoolExecutor(1).submit(new Callable() {
            public Object call() throws Exception {
                System.out.println(Thread.currentThread().getName() + " is running");
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    System.out.println(Thread.currentThread().getName() + " 抛出了异常，即将中断线程操作执行回滚");
                    throw e;
                } finally {
                    ObserveThread.latch.countDown();
                }
                return null;
            }
        });
        try {
            if (f.get() != null) {
                throw new RuntimeException("抛出了runTimeException");
            }
        } catch (Exception e) {
            throw new RuntimeException("抛出了runTimeException");
        }
    }

}
